/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */

#include "MaterialManager.h"

#include "FileSystem.h"
#include "GPKArchiveManager.h"

namespace PQEngine
{

	GPKMaterialCompilerListener::GPKMaterialCompilerListener(Ogre::String materialPath)
		: _materialPath(materialPath)
	{
		_parentPath=FileSystem::getParentPath(_materialPath);
	}

	GPKMaterialCompilerListener::~GPKMaterialCompilerListener()
	{
	}
	
	Ogre::ConcreteNodeListPtr GPKMaterialCompilerListener::importFile(Ogre::ScriptCompiler *compiler, const Ogre::String &name)
	{
		return Ogre::ConcreteNodeListPtr();
	}

	void GPKMaterialCompilerListener::preConversion(Ogre::ScriptCompiler *compiler, Ogre::ConcreteNodeListPtr nodes)
	{
	}

	bool GPKMaterialCompilerListener::postConversion(Ogre::ScriptCompiler *compiler, const Ogre::AbstractNodeListPtr& ptr)
	{
		return true;
	}
	
	void GPKMaterialCompilerListener::handleError(Ogre::ScriptCompiler *compiler, unsigned int code, const Ogre::String &file, int line, const Ogre::String &msg)
	{
	}

	bool GPKMaterialCompilerListener::handleEvent(Ogre::ScriptCompiler *compiler, Ogre::ScriptCompilerEvent *evt, void *retval)
	{
		if(evt->mType==Ogre::ProcessResourceNameScriptCompilerEvent::eventType){
			Ogre::ProcessResourceNameScriptCompilerEvent* pevt=(Ogre::ProcessResourceNameScriptCompilerEvent*)evt;
			if(pevt->mResourceType==Ogre::ProcessResourceNameScriptCompilerEvent::TEXTURE){
				Ogre::String textureName=pevt->mName;
				Ogre::String texturePath=_parentPath+"/";

				texturePath+=textureName;

				loadGPKTexture(texturePath,textureName);//must unique,so .gpk is better to be one level 
				return true;//process by this function
			}
		}
		return false;//left to ogre process
	}

	void GPKMaterialCompilerListener::loadGPKTexture(Ogre::String texturePath,Ogre::String textureName)
	{
		GPKFile* file=GNgGPKArchiveManager.getFile(texturePath);
		if(!file||!file->ok()){
			return;
		}

		file->open();
		int size=file->length();
		char* buf=new char[size];
		file->read(buf,size);
		file->close();

		Ogre::DataStreamPtr stream=Ogre::DataStreamPtr(new Ogre::MemoryDataStream(buf,size));

		Ogre::Image img;
		img.load(stream);

		Ogre::TextureManager::getSingleton().loadImage(textureName,
			Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
			img);

		delete buf;

	}


	const std::string GameMaterialManager::DEFAULT_MATERIAL_NAME="Material/Basic/Default";
	const std::string GameMaterialManager::WHITE_MATERIAL_NAME="Material/Basic/White";
	const std::string GameMaterialManager::GRAY_MATERIAL_NAME="Material/Basic/Gray";
	const std::string GameMaterialManager::DARK_MATERIAL_NAME="Material/Basic/Dark";
	const std::string GameMaterialManager::WIREFRAME_MATERIAL_NAME="Material/Basic/Wireframe";

	GameMaterialManager::GameMaterialManager()
	{
		init();
	}

	GameMaterialManager& GameMaterialManager::getSingleton()
	{
		static GameMaterialManager inst;
		return inst;
	}

	void GameMaterialManager::load(Ogre::String meshName)
	{
		std::string matFileName=GFileBaseSystem.changeExt(meshName,GFileBaseSystem.EXT_MATERIAL);
		GPKFile* file=GNgGPKArchiveManager.getFile(matFileName);
		if(!file||!file->ok()){
			return;
		}

		file->open();
		int size=file->length();
		char* buf=new char[size];
		file->read(buf,size);
		file->close();

		Ogre::DataStreamPtr stream=Ogre::DataStreamPtr(new Ogre::MemoryDataStream(buf,size));
		
		GPKMaterialCompilerListener* listener=new GPKMaterialCompilerListener(matFileName);

		Ogre::ScriptCompilerManager::getSingleton().setListener(listener);
		Ogre::ScriptCompilerManager::getSingleton().parseScript(stream,Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
		delete listener;
		delete buf;

	}

	void GameMaterialManager::init()
	{
		createDefaultMaterial();
		createWireframeMaterial();
		
	}

	Ogre::MaterialPtr GameMaterialManager::createWireframeMaterial()
	{
		Ogre::MaterialPtr material=Ogre::MaterialManager::getSingleton().create(WIREFRAME_MATERIAL_NAME,Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
		
		material->getTechnique(0)->getPass(0)->setPolygonMode(Ogre::PM_WIREFRAME);
		material->getTechnique(0)->getPass(0)->setPolygonModeOverrideable(false);
		
		material->getTechnique(0)->getPass(0)->setAmbient(0,0,0);
		material->getTechnique(0)->getPass(0)->setDiffuse(Ogre::ColourValue(1,1,1));
		material->getTechnique(0)->getPass(0)->setSpecular(Ogre::ColourValue(0,0,1));
		material->getTechnique(0)->getPass(0)->setSelfIllumination(Ogre::ColourValue(1,1,1,1));

		return material;
	}

	Ogre::MaterialPtr GameMaterialManager::createDefaultMaterial()
	{
		Ogre::MaterialPtr material=Ogre::MaterialManager::getSingleton().create(DEFAULT_MATERIAL_NAME,Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
		
		material->getTechnique(0)->getPass(0)->setPolygonMode(Ogre::PM_SOLID);
		material->getTechnique(0)->getPass(0)->setCullingMode(Ogre::CULL_NONE);
		material->getTechnique(0)->getPass(0)->setDiffuse(Ogre::ColourValue(1,0,0.8));
		material->getTechnique(0)->getPass(0)->setAmbient(Ogre::ColourValue(1,1,1));
		return material;
	}

	Ogre::MaterialPtr GameMaterialManager::createDefaultMaterial(Ogre::String name)
	{
		Ogre::MaterialPtr material=Ogre::MaterialManager::getSingleton().getByName(name);
		if(!material.isNull()){
			return material;
		}

		material=Ogre::MaterialManager::getSingleton().create(name,Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
		material->getTechnique(0)->getPass(0)->setLightingEnabled(false);
		material->getTechnique(0)->getPass(0)->setPolygonMode(Ogre::PM_WIREFRAME);
		material->getTechnique(0)->getPass(0)->setDiffuse(Ogre::ColourValue(0.5,0.5,0.5));
		//material->getTechnique(0)->getPass(0)->setSelfIllumination(Ogre::ColourValue(0.5,0.5,0.5));
		return material;
	}

}
